package me.w70.fps.actor;

import me.w70.fps.constants.Angles;
import me.w70.fps.map.Cell;
import me.w70.fps.map.Map;
import me.w70.fps.render.GameWindow;

public class Player {
	// Pointers to objects needed
	protected GameWindow renderer;
	protected Angles angles;
	// Map data
	protected Map mapptr;
	protected Cell[] map;
	protected int mapx;
	protected int mapy;
	protected int TILE_SIZE;
	// Player data
	protected int x = 100;
	protected int y = 100;
	protected int height = 0;
	protected int angle = 0;
	protected int hp;
	protected int armor;
	// Constant, should NOT exceed TILE_SIZE / 2 or collision detection will fail in some cases.
	protected static int basespeed = 23;
	protected int speed = basespeed;
    public float[] sintable;
    public float[] costable;
	
    // Use collision detection for movement?
	protected boolean usecollisiondetection;
	// Use images?
	private boolean useimages;
	
	// Getters + setters
	public int getX() { return x; }
	public void setX(int x) { this.x = x; }
	
	public int getY() { return y; }
	public void setY(int y) { this.y = y; }
	
	public int getHeight() { return height; }
	public void setHeight(int h) { this.height = h; }
	
	public int getAngle() { return angle; }
	// When setting the angle, make sure we wrap around properly.
	public void setAngle(int angle) { 
		this.angle = angle; 
    	if (this.angle < angles.ANGLE0) {
    		this.angle += angles.ANGLE360; 
    	}
    	else if (this.angle >= angles.ANGLE360) {
    		this.angle -= angles.ANGLE360; 
    	} 
    }
	
	public int getHp() { return hp; }
	public void setHp(int hp) { this.hp = hp; }
	
	public int getArmor() { return armor; }
	public void setArmor(int armor) { this.armor = armor; }
	
	public int getSpeed() { return speed; }
	public void setSpeed(int speed) { this.speed = speed; }
	
	// Set the renderer to be used (should be GameWindow).
	public void setRenderer(GameWindow gw) {
		this.renderer = gw;
	}
	
	// Set the player's starting position to the map's start position.
	public void getStartPosition() {
		this.x = mapptr.getStartX() * TILE_SIZE;
		this.y = mapptr.getStartY() * TILE_SIZE;
	}
	
	// Setup variables
	public Player(Angles anglesobject, Map map, boolean collisiondetect, boolean useimages) {
		this.angles = anglesobject;
		this.mapptr = map;
		this.usecollisiondetection = collisiondetect;
		this.useimages = useimages;
		this.TILE_SIZE = map.TILE_SIZE;
		this.map = map.getMap();
		this.mapx = map.getMapx();
		this.mapy = map.getMapy(); 
		this.getStartPosition();
	}
	
	// Check for movement, player actions, etc.
	public void move(boolean KeyLeft, boolean KeyRight, boolean KeyUp, boolean KeyDown, boolean KeyCtrl, boolean KeyAlt, boolean KeySpace, boolean KeyShift) {
		int xdir = 0;
		int ydir = 0;
		int moveangle = this.angle;
		
		// Spacebar
		if (KeySpace) {
			// Check in front of the player.
			float xangle = costable[moveangle];
			int checkxdir = (int)(xangle * this.speed); 
			float yangle = sintable[moveangle];
			int checkydir = (int)(yangle * this.speed);
			int newspacex = ((int)(this.x + (checkxdir * 3)) / TILE_SIZE) + ((int)((this.y / TILE_SIZE) * mapx));
			int newspacey = ((int)this.x / TILE_SIZE) + ((int)(((this.y + (checkydir * 3)) / TILE_SIZE) * mapx));
			if (map[newspacex].mapchar == '|') {
				System.out.println("We hit a door!");
				this.mapptr.doormap.get(newspacex).status = 1;
			}
			if (map[newspacey].mapchar == '|') {
				System.out.println("We hit a door!");
				this.mapptr.doormap.get(newspacey).status = 1;
			}
			if (map[newspacex].mapchar == 'E') {
				System.out.println("We hit the elevator!");
			}
			if (map[newspacey].mapchar == 'E') {
				System.out.println("We hit the elevator!");
			}
		}
		
		// Shift
		if (KeyShift) {
			this.speed = basespeed * 2;
		}
		else {
			this.speed = basespeed;
		}
		
		if (KeyCtrl) {
			this.height = -30;
		}
		else {
			this.height = 0;
		}
		
		// Left
		if (KeyLeft) {
			if (!KeyAlt) {
				setAngle(this.angle - angles.ANGLE10);
				moveangle = this.angle; 
			}
			else {
				moveangle = this.angle - angles.ANGLE90;
				if (moveangle < angles.ANGLE0) {
					moveangle += angles.ANGLE360;
				}
				float xangle = costable[moveangle];
				xdir = (int)(xangle * this.speed);
			}
		}
		// Right
		else if (KeyRight) {
			if (!KeyAlt) {
				setAngle(this.angle + angles.ANGLE10);
				moveangle = this.angle; 
			}
			else {
				moveangle = this.angle - angles.ANGLE90;
				if (moveangle > angles.ANGLE360) {
					moveangle -= angles.ANGLE360;
				}
			}
		}

		// Up
		if (KeyUp) {
			// X and Y components of angle for calculating movement
			if (!KeyAlt) {
				float xangle = costable[moveangle];
				xdir = (int)(xangle * this.speed); 
			}
			float yangle = sintable[moveangle];
			ydir = (int)(yangle * this.speed);
            // Get the player's new map coordinates. If we're now inside a wall or other object, use old x + y.
			if (usecollisiondetection && map[(this.x / TILE_SIZE) + ((this.y / TILE_SIZE) * mapx)].mapchar != '|') {
				int newmapx = ((int)(this.x + (xdir * 2)) / TILE_SIZE) + ((int)((this.y / TILE_SIZE) * mapx));
				int newmapy = ((int)(this.x / TILE_SIZE) + ((int)(((this.y + (ydir * 2)) / TILE_SIZE) * mapx)));
				if (map[newmapx].mapchar != '0') {
					if (useimages && map[newmapx].mapchar != '|') {
						xdir = 0;
					}
					else {
						if (this.mapptr.doormap.get(newmapx).status != 2) {
							xdir = 0; 
						}
					}
				}
				if (map[newmapy].mapchar != '0') {
					if (useimages && map[newmapy].mapchar != '|') {
						ydir = 0;
					}
					else {
						if (this.mapptr.doormap.get(newmapy).status != 2) {
							ydir = 0; 
						}
					}
				}
				
			}
            
            this.setX(this.x + xdir);
            this.setY(this.y + ydir);
		}
		// Down
		else if (KeyDown) {
			// Same as up but we move backwards.
			
			if (!KeyAlt) {
				float xangle = costable[moveangle];
				xdir = (int)(xangle * -this.speed); 
			}
			float yangle = sintable[moveangle];
			ydir = (int)(yangle * -this.speed);
			if (usecollisiondetection) {

				int newmapx = ((int)(this.x + (xdir * 2)) / TILE_SIZE) + ((int)((this.y / TILE_SIZE) * mapx));
				int newmapy = ((int)(this.x / TILE_SIZE) + ((int)(((this.y + (ydir * 2)) / TILE_SIZE) * mapx)));
				if (map[newmapx].mapchar != '0') {
					if (useimages && map[newmapx].mapchar != '|') {
						xdir = 0;
					}
					else {
						if (this.mapptr.doormap.get(newmapx).status != 2) {
							xdir = 0; 
						}
					}
				}
				if (map[newmapy].mapchar != '0') {
					if (useimages && map[newmapy].mapchar != '|') {
						ydir = 0;
					}
					else {
						if (this.mapptr.doormap.get(newmapy).status != 2) {
							ydir = 0; 
						}
					}
				}
			}
            this.setX(this.x + xdir);
            this.setY(this.y + ydir);
		}
	}
}
